﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.ComponentModel;
using System.Net;

namespace ConsoleApp
{
    public static class 学习Task
    {
        /// <summary>
        /// 注意顺序可能不同
        /// </summary>
        public static void 简单使用1()
        {
            var t1 = new Task(() =>
            {
                Console.WriteLine("123");
            });
            t1.Start();
            Console.WriteLine("hello from the calling thread.");
        }

        public static void 使用StartNew()
        {
            var t1 = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("123");
            });
            Console.WriteLine("hello from the calling thread.");
        }

        public static void 多个Task()
        {
            var tasks = new Task<double>[]
            {
                Task<double>.Factory.StartNew(()=>1D),
                Task<double>.Factory.StartNew(()=>2D),
                Task<double>.Factory.StartNew(()=>3D),
            };
            for (int i = 0; i < tasks.Length; i++)
                Console.WriteLine(tasks[i].Result.ToString());
        }

        public static void 传递数据()
        {
            var tasks = new Task[10];
            for (int i = 0; i < tasks.Length; i++)
            {
                tasks[i] = new Task((obj) =>
                {
                    var foo = (Foo)obj;
                    foo.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                    Console.WriteLine("task #{0} created at #{1} running on thread #{2}.",
                        foo.Name.ToString(),
                        foo.Time.ToString(),
                        foo.ThreadNum.ToString());
                }, new Foo { Name = i, Time = DateTime.Now.Ticks });
                tasks[i].Start();
                Console.WriteLine(tasks[i].Id.ToString());
            }
        }

        public static void WaitAll()
        {
            var tasks = new Task[4]
            {
                Task.Factory.StartNew(()=>{ Console.WriteLine("1"); }),
                Task.Factory.StartNew(()=>{ Console.WriteLine("2"); }),
                Task.Factory.StartNew(()=>{ Console.WriteLine("3"); }),
                Task.Factory.StartNew(()=>{ Console.WriteLine("4"); }),
            };
            Task.WaitAll(tasks);
            Console.WriteLine("all task completed.");
        }

        public static void Parallel_Invoke()
        {
            Parallel.Invoke(() =>
            {
                Console.WriteLine("1");
            }, () =>
            {
                Console.WriteLine("2");
            }, () =>
            {
                Console.WriteLine("3");
            }, () =>
            {
                Console.WriteLine("4");
            }, () =>
            {
                Console.WriteLine("5");
            }, () =>
            {
                Console.WriteLine("6");
            });
        }

        public static void 分离的嵌套Task()
        {
            //outer不会等待inner完成
            var outer = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("outer task begining.");
                var inner = Task.Factory.StartNew(() =>
                {
                    Thread.SpinWait(5000000);
                    Console.WriteLine("detached task completed.");
                });
            });
            outer.Wait();
            Console.WriteLine("outer task completed.");
        }

        public static void 子任务()
        {
            var parentTask = Task.Factory.StartNew(() =>
            {
                Console.WriteLine("parent task beginning.");
                var childTask = Task.Factory.StartNew(() =>
                {
                    Thread.SpinWait(5000000);
                    Console.WriteLine("attached child completed.");
                }, TaskCreationOptions.AttachedToParent);
            });
            parentTask.Wait();
            Console.WriteLine("parent task completed.");
        }

        public static void ContinueWith()
        {
            var rnd = new Random();
            var t1 = new Task<int>(() =>
            {
                return rnd.Next(0, 1000);
            });
            var t2 = t1.ContinueWith(t =>
            {
                return t.Result >= 500;
            });
            var t3 = t2.ContinueWith(t =>
            {
                Console.WriteLine((t.Result ? "good" : "bad"));
            });
            t1.Start();
        }

        public static void ContinueWith_返回值()
        {
            var t1 = new Task<DayOfWeek>(() =>
            {
                return DateTime.Today.DayOfWeek;
            });
            var t2 = t1.ContinueWith(t =>
            {
                Thread.Sleep(1000);
                return string.Format("today is {0}", t.Result.ToString());
            });
            t1.Start();
            //访问了Result属性，自动等待结束？
            Console.WriteLine(t2.Result);
        }

        public static void ContinueWhenAll()
        {
            var tasks = new Task<int>[2];
            tasks[0] = new Task<int>(() => { return 15; });
            tasks[1] = new Task<int>(() => { return 75; });
            var t3 = Task.Factory.ContinueWhenAll(tasks, (t) =>
            {
                Console.WriteLine(t.Sum(o => o.Result).ToString());
            });
            tasks[0].Start();
            tasks[1].Start();
        }

        public static void 取消任务()
        {
            var cts = new CancellationTokenSource();
            var t1 = Task.Factory.StartNew(() =>
            {
                var ct = cts.Token;
                var i = 0;
                while (i < 1000)
                {
                    ct.ThrowIfCancellationRequested();
                    Console.Write((i++).ToString());
                    Console.Write(",");
                }
            }, cts.Token);
            var t2 = t1.ContinueWith(t =>
            {
                var i = 888;
                while (i > 0)
                {
                    Console.Write((i--).ToString());
                }
            }, cts.Token);
            Thread.Sleep(10);
            cts.Cancel();
        }

        public static void 取消任务2()
        {
            var cts = new CancellationTokenSource();
            var ct = cts.Token;
            var t1 = Task.Factory.StartNew(() =>
            {
                ct.ThrowIfCancellationRequested();
                var i = 0;
                while (true)
                {
                    Console.WriteLine((i++).ToString());
                    ct.ThrowIfCancellationRequested();
                }
            }, cts.Token);
            Thread.Sleep(100);
            cts.Cancel();

            try
            {
                t1.Wait();
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.InnerExceptions)
                    Console.WriteLine(ae.Message + " " + e.Message);
            }
        }

        public static void 延续任务_异常()
        {
            var t1 = Task<int>.Factory.StartNew(() => 54);
            var t2 = t1.ContinueWith(t =>
            {
                Console.WriteLine("t1 result #{0}", t.Result);
                throw new InvalidOperationException();
            });
            try
            {
                t1.Wait();
                t2.Wait();
            }
            catch (AggregateException ae)
            {
                foreach (var item in ae.InnerExceptions)
                    Console.WriteLine(item.Message);
            }
            Console.WriteLine("exception handled, let's move on.");
        }

        public static void 异常()
        {
            var t1 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm bad,but not too bad!");
            });
            try
            {
                t1.Wait();
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.InnerExceptions)
                {
                    if (e is MyCustomException)
                    {
                        Console.WriteLine(e.Message);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }

        public static void 多个异常()
        {
            var t1 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm a bad boy.");
            });
            var t2 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm a bad man.");
            });
            try
            {
                Task.WaitAll(t1, t2);
            }
            catch (AggregateException ae)
            {
                foreach (var e in ae.InnerExceptions)
                {
                    if (e is MyCustomException)
                    {
                        Console.WriteLine(e.Message);
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }

        public static void 附加子任务异常()
        {
            var outerTask = Task.Factory.StartNew(() =>
            {
                var innerTask = Task.Factory.StartNew(() =>
                {
                    var inInnerTask = Task.Factory.StartNew(() =>
                    {
                        throw new MyCustomException("it's all my fault.");

                    }, TaskCreationOptions.AttachedToParent);

                    throw new MyCustomException("no,it's my fault.");

                }, TaskCreationOptions.AttachedToParent);
            });
            try
            {
                outerTask.Wait();
            }
            catch (AggregateException ae)
            {
                PrintAggregateException(ae);
                foreach (var e in ae.InnerExceptions)
                {
                    if (e is MyCustomException)
                        continue;

                    if (e is AggregateException)
                        continue;

                    throw;
                }
            }
        }

        public static void 分离子任务异常()
        {
            var outerTask = Task.Factory.StartNew(() =>
            {
                var innerTask = Task.Factory.StartNew(() =>
                {
                    throw new MyCustomException("555555.");
                });

                //注释这行将没有异常信息显示！
                innerTask.Wait();
            });
            try
            {
                outerTask.Wait();
            }
            catch (AggregateException ae)
            {
                PrintAggregateException(ae);
                foreach (var e in ae.InnerExceptions)
                {
                    if (e is MyCustomException)
                        continue;

                    if (e is AggregateException)
                        continue;

                    throw;
                }
            }
        }

        public static void 使用Task_Exception属性()
        {
            var t1 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm sorry");
            });
            var t2 = t1.ContinueWith(t =>
            {
                Console.WriteLine(t.Exception.InnerException.Message);
                Console.WriteLine(t.Exception.InnerException.GetType().Name);
            }, TaskContinuationOptions.OnlyOnFaulted);
        }

        public static void ParallelInvoke2()
        {
            var words = CreateWordArray(@"http://www.gutenberg.org/files/2009/2009.txt");
            Parallel.Invoke(() =>
            {
                Console.WriteLine("begin first task.");
                GetLongestWord(words);
            }, () =>
            {
                Console.WriteLine("begin second task.");
                GetMostCommonWords(words);
            }, () =>
            {
                Console.WriteLine("begin third task.");
                GetCountForWord(words, "species");
            });
            Console.WriteLine("returned from Parallel.Invoke");
        }


        private static void GetCountForWord(string[] words, string p)
        {
            var findWords = words.Where(w => w.ToUpper().Contains(p.ToUpper()));
            Console.WriteLine(@"task 3 -- the word ""{0}"" occurs {1} times.", p, findWords.Count());
        }

        private static void GetMostCommonWords(string[] words)
        {
            var commonWords = words
                .Where(w => w.Length > 6)
                .GroupBy(w => w)
                .OrderByDescending(g => g.Count())
                .Select(g => g.Key)
                .Take(10);

            Console.WriteLine("task 2 -- the most common words are:{0}", string.Join("  ", commonWords.ToArray()));
        }

        private static string GetLongestWord(string[] words)
        {
            var longestWord = words.OrderByDescending(w => w.Length).First();
            Console.WriteLine("task 1 -- the longest word is {0}", longestWord);
            return longestWord;
        }

        private static string[] CreateWordArray(string url)
        {
            Console.WriteLine("retrieving from {0}", url);
            var s = new WebClient().DownloadString(url);
            return s.Split(new char[]
            {
                ' ', '\u000A', ',', '.', ';', ':', '-', '_', '/'
            }, StringSplitOptions.RemoveEmptyEntries);
        }

        /// <summary>
        /// 这个方法没用，不知道为什么
        /// </summary>
        public static void UnobservedTaskException事件()
        {
            TaskScheduler.UnobservedTaskException += (sender, e) =>
            {
                e.SetObserved();
                e.Exception.Handle(ex =>
                {
                    Console.WriteLine(ex.Message);
                    return true;
                });
            };
            var t1 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm sorry 1");
            });
            var t2 = Task.Factory.StartNew(() =>
            {
                throw new MyCustomException("i'm sorry 2");
            });

           
            Task.WaitAll(t1, t2);
        }


        private static void PrintAggregateException(AggregateException ae)
        {
            foreach (var e in ae.InnerExceptions)
            {
                if (e is MyCustomException)
                    Console.WriteLine(e.Message);

                if (e is AggregateException)
                    PrintAggregateException(e as AggregateException);
            }
        }
    }

    class Foo
    {
        public long Time { get; set; }
        public int Name { get; set; }
        public int ThreadNum { get; set; }
    }

    public class MyCustomException : Exception
    {
        public MyCustomException(string message)
            : base(message)
        { }
    }
}